#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @author: Florian Dorn <florian.dorn@gmail.com>
# @package: agenda
# @license: GNU GPLv2
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

import gtk
import gobject
import datetime
from DateWidget import DateWidget

from agenda import get_timeout_add_time
import math
from gettext import gettext as _


#from MouseOverLabel import MouseOverLabel


def gtk_color2cairo_rgb(color):
	return map(lambda x: x/65535.0,(color.red,color.green,color.blue))


class AgendaListView (gtk.VBox):
	__gtype_name__ = 'AgendaListView'
	__gproperties__ = {
		'period': ( gobject.TYPE_PYOBJECT, 'period',"Period", gobject.PARAM_READWRITE )
	}
	"""The list-view of the agenda"""
	def __init__(self,appointment):
		#BASE, BG, FG
		self.palette = "BASE"
		gtk.VBox.__init__(self,False)
		self.show()
		self.current_rows = []
		self.date_widgets = {}
		self._recolor_requested_id = None #
		
		self._attributes = { 'period': appointment.get_period() }
		
		item_storage = appointment.item_storage
		item_storage.connect('item-added',    self.storage_item_inserted_cb)
		item_storage.connect('item-removed',  self.storage_item_removed_cb)
		item_storage.connect('items-changed',	self.storage_items_changed_cb)
		
		#bg colors are [0-1]
		self.color_today_bg = (.9,.9,0)
		self.color_odd_bg = (.9,.9,.9)
		self.color_even_bg = (1,1,1)
		
		#fg_colors are gtk_colors
		self.color_today_fg = None
		self._style_source = self.connect ("notify::style", self.set_styles) # gtk theme changes
		
		self.set_styles()
		self.updateView(item_storage)
		
		
		self.maintain_view()
		self._filter = None
		appointment.connect('config-change',self.config_change_cb)
		
		self.connect_after("notify::period",self.on_period_changed_cb)
		print datetime.datetime.now()
		pass
	def on_period_changed_cb(self,a,b):
		self.maintain_view()

	def do_get_property(self, pspec):
		if pspec.name in self._attributes:
			return self._attributes[pspec.name]
		else:
			raise AttributeError, 'unknown property %s' % pspec.name
	
	def do_set_property(self, pspec, value):
		if pspec.name in self._attributes:
			self._attributes[pspec.name] = value
		else:
			raise AttributeError, 'unknown property %s' % pspec.name
	
	def config_change_cb(self,appointments,path,value):
		if path == 'num_days':
			p = appointments.get_period()
			self.set_period(p)
	def set_styles (self, obj=None, prop=None):
		"""
		update the style
		"""
		DateWidget.color_today_bg = gtk_color2cairo_rgb(self.style.bg[gtk.STATE_SELECTED])
		DateWidget.color_today_fg = self.style.fg[gtk.STATE_SELECTED]

	def add_date_widget(self,date):
		"""
		Get the DateWidget
		"""
		if not self.date_widgets.has_key(date):
			#todo: maintain order in the dates
			d = DateWidget(date)
			self.date_widgets[date] = d
			new_pos = -1
			self.pack_start(d,False,False)
			d.connect("notify::visible",self.child_visibility_changed)
			for i,child in enumerate(self.get_children()):
				if(child.date > date):
					self.reorder_child(d,i)
					break
			if(not self.get_period().inside(date)):
				d.hide()
		return self.date_widgets[date]

	def filter(self,filter):
		"""
		filter the view
		"""
		if(self._filter == filter):
			return
		found_any = False
		now = datetime.datetime.now()
		for widget in self.get_children():
			if isinstance(widget,DateWidget) and self.is_datewidget_in_period(widget):
				found = widget.filter(filter)				
				if(found):				
					found_any = True
		self._filter = filter
		return found_any

	def actual_recoloring(self):
		#print "recoloring..."
		k=0
		for date_widget in self.get_children():
			if date_widget.is_visible():
				k = k+1
				date_widget.set_row_number(k)
		gobject.source_remove(self._recolor_requested_id)
		
		self._recolor_requested_id = None
		gobject.idle_add(self.queue_draw)
		
		return False
	def request_recoloring(self):
		"""
		request recoloring. This is delayed, to reduce the amount of actual recolors
		"""
		#if not self._recolor_requested_id :
		#	self._recolor_requested_id = gobject.timeout_add(10,self.actual_recoloring)
		if self._recolor_requested_id:
			gobject.source_remove(self._recolor_requested_id)
		self._recolor_requested_id = gobject.timeout_add(10,self.actual_recoloring)
	
		
	def storage_item_inserted_cb(self,storage,item):
		"""
		connect this to the storage to keep the list view updated if new items are added
		"""
		for e in item.expand():
			date = e.getStartDate()
			date_widget = self.add_date_widget(date)
			if(item.is_visible() and not date_widget.is_visible()):
				date_widget.show_all()
			date_widget.add_event(e)

	def storage_item_removed_cb(self,storage,item):
		"""
		connect this to the storage to keep the list view updated if new items are added
		"""
		#print "'%s' should be removed " % item
		for e in item.expand():
			date = e.getStartDate()
			dw = self.date_widgets[date]
			
			if dw != None:
				dw.remove_event(e)
		#else:
		#	"... is not in list"

	def storage_items_changed_cb(self,storage,item_list):
		for item in item_list:
			print item

	def updateView(self,item_storage):
		for item in item_storage.get_items():
			self.storage_item_inserted_cb(item_storage, item)

	def child_visibility_changed(self,date_widget, pspec):
		"""
		if the visibilty of a date_widget is changed, the list has to be recolored
		"""
		#print "widget vis changed", date_widget
		if(self.is_datewidget_in_period(date_widget)):
			self.request_recoloring()
		else:
			date_widget.hide()
		
	def get_period(self):
		return self._attributes['period']
	def set_period(self,period):
		self.set_property("period",period)
	def maintain_view(self):
		"""
		maintain a valid view:
		1. check if only dates are visible that are in the period
		2. install a timout_add, to remaintain on the next day change
		"""
		today = datetime.date.today()
		today_widget = self.add_date_widget(today)
		today_widget.show_all()
		for widget in self.date_widgets.values():
			if not self.is_datewidget_in_period(widget):
				
				widget.hide()
			else:
				
				widget.show()
		nextdraw_micro = get_timeout_add_time( datetime.datetime.combine(datetime.date.today(),datetime.time()) + datetime.timedelta(days=1) )
		gobject.timeout_add(nextdraw_micro,self.maintain_view)
		return False
	def is_datewidget_in_period(self,widget):
		return self._attributes['period'].inside( widget.date)
	def do_expose_event(self, event):
		
		allocation = self.get_allocation()
		style = self.get_style()
		state = self.state

		if self.palette == 'BASE':
			gc = style.base_gc[state]
		elif self.palette == 'BG':
			gc = style.bg_gc[state]
		elif self.palette == 'FG':
			gc = style.fg_gc[state]
		else:
			gtk.VBox.do_expose_event(self, event)
			return

		self.window.draw_rectangle(gc, True, allocation.x, allocation.y, allocation.width, allocation.height)
		
		gtk.VBox.do_expose_event(self, event)
		pass
def new_next_update_time(next_update,new,now):
	
	if (new > next_update):
		return next_update
	if (new < now):
		return next_update
	
	return min(new,next_update)
